package com.intellekt.ecertws.ws.endpoint;

import static com.intellekt.ecertws.domain.Constants.ACKNOWLEDGE_CLOSE_TAG;
import static com.intellekt.ecertws.domain.Constants.ACKNOWLEDGE_OPEN_TAG;
import static com.intellekt.ecertws.domain.Constants.ID_CLOSE_TAG;
import static com.intellekt.ecertws.domain.Constants.ID_OPEN_TAG;
import static com.intellekt.ecertws.domain.Constants.INFO_CLOSE_TAG;
import static com.intellekt.ecertws.domain.Constants.INFO_OPEN_TAG;
import static com.intellekt.ecertws.domain.Constants.REJECT_CLOSE_TAG;
import static com.intellekt.ecertws.domain.Constants.REJECT_OPEN_TAG;
import static com.intellekt.ecertws.domain.Constants.SERVICE_NS;
import static com.intellekt.ecertws.domain.Constants.XML_DECLARATION;
import static com.intellekt.ecertws.domain.DomainUtils.encode;
import static com.intellekt.ecertws.domain.DomainUtils.validDateRange;

import java.io.StringWriter;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Source;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
import org.springframework.xml.transform.StringSource;

import un.unece.uncefact.data.standard.spscertificate._6.AcknowledgeCertificateByIDRequest;
import un.unece.uncefact.data.standard.spscertificate._6.CertificateByIDRequest;
import un.unece.uncefact.data.standard.spscertificate._6.CertificateByInfoRequest;
import un.unece.uncefact.data.standard.spscertificate._6.ObjectFactory;
import un.unece.uncefact.data.standard.spscertificate._6.SPSCertificateType;

import com.intellekt.ecertws.ws.service.CertService;

/**
 * 
 * An annotated end-point that will be automatically detected by the Spring-WS
 * framework, and handled by the appropriate adapter.
 * 
 */
@Endpoint
public class EcertServiceEndpoint{

	private static final Logger log = Logger.getLogger(EcertServiceEndpoint.class);

	@Autowired
	private CertService infoService;

	private Object unmarshal(Source source, @SuppressWarnings("rawtypes") Class clazz) throws Exception {
		JAXBContext context;
		try {
			context = JAXBContext.newInstance(clazz);
			Unmarshaller um = context.createUnmarshaller();
			return um.unmarshal(source);
		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	public String marshal(Object pObject) throws Exception {
		JAXBContext jc = JAXBContext.newInstance(un.unece.uncefact.data.standard.spscertificate._6.SPSCertificateType.class);
		StringWriter sw = new StringWriter();

		Marshaller marshaller = jc.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
		marshaller.setProperty("jaxb.fragment", Boolean.TRUE);
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
		marshaller.marshal(pObject, sw);

		return sw.toString();
	}

	@PayloadRoot(localPart = "acknowledgeCertificateByIDRequest", namespace = SERVICE_NS)
	public @ResponsePayload Source handleAcknowledgeCertificateByIDRequest(@RequestPayload Source source) throws Exception {

		AcknowledgeCertificateByIDRequest request = (AcknowledgeCertificateByIDRequest) unmarshal(source, AcknowledgeCertificateByIDRequest.class);

		String refNumber = request.getCertNumber();
		String fName = request.getReason();

		System.out.println(refNumber + " " + fName);

		return new StringSource(ACKNOWLEDGE_OPEN_TAG + "OK" + ACKNOWLEDGE_CLOSE_TAG);
	}

	@PayloadRoot(localPart = "rejectCertificateByIDRequest", namespace = SERVICE_NS)
	public @ResponsePayload Source handleRejectCertificateByIDRequest(@RequestPayload Source source) throws Exception {

		AcknowledgeCertificateByIDRequest request = (AcknowledgeCertificateByIDRequest) unmarshal(source, AcknowledgeCertificateByIDRequest.class);

		String refNumber = request.getCertNumber();
		String fName = request.getReason();

		System.out.println(refNumber + " " + fName);

		return new StringSource(REJECT_OPEN_TAG + "OK" + REJECT_CLOSE_TAG);
	}

	@PayloadRoot(localPart = "certificateByInfoRequest", namespace = SERVICE_NS)
	public @ResponsePayload Source handleCertificateByInfoRequest(@RequestPayload Source source) throws Exception {
		CertificateByInfoRequest request = (CertificateByInfoRequest) unmarshal(source, CertificateByInfoRequest.class);

		String from = request.getDateIssueFrom();
		String to = request.getDateIssueTo();
		String issueCountry = request.getIssueCountry();
		String issueLocation = request.getIssueLocation();

		if (log.isDebugEnabled()) {
			log.debug("handleCertificateByInfoRequest...");
			log.debug("from..." + from);
			log.debug("to..." + to);
			log.debug("issueCountry..." + issueCountry);
			log.debug("issueLocation..." + issueLocation);
		}
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
	    String name = auth.getName();

		validDateRange(from, to);
		List<SPSCertificateType> certificates = infoService.getCertificatesByInfo(from, to, issueCountry, issueLocation, name);
		return new StringSource(formatResponseByInfo(certificates, true));
	}

	@PayloadRoot(localPart = "certificateByIDRequest", namespace = SERVICE_NS)
	public @ResponsePayload Source handleCertificateByIDRequest(@RequestPayload Source source) throws Exception {
		
		if (log.isDebugEnabled()) {
			log.debug("handleCertificateByIDRequest...");
		}
		
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
	    String name = auth.getName();
	    
		CertificateByIDRequest request = (CertificateByIDRequest) unmarshal(source, CertificateByIDRequest.class);

		String idCert = request.getIdCertificate();

		if (log.isDebugEnabled()) {
			log.debug("handleCertificateByInfoRequest...");
			log.debug("idCert..." + idCert);
		}

		List<SPSCertificateType> certificates = infoService.getCertificatesById(idCert, name);

		return new StringSource(formatResponseById(certificates, true));
	}

	public String formatResponseById(List<SPSCertificateType> certificates, boolean islist) throws Exception {

		ObjectFactory objectFactory = new ObjectFactory();
		StringBuffer sb = new StringBuffer();
		sb.append(XML_DECLARATION);

		sb.append(System.getProperty("line.separator"));

		for (SPSCertificateType cert : certificates) {

			JAXBElement<SPSCertificateType> je = objectFactory.createSPSCertificate(cert);

			sb.append(marshal(je));
			sb.append(System.getProperty("line.separator"));
		}

		String response = ID_OPEN_TAG + encode(sb.toString()) + ID_CLOSE_TAG;

		return response;
	}

	public String formatResponseByInfo(List<SPSCertificateType> certificates, boolean islist) throws Exception {

		ObjectFactory objectFactory = new ObjectFactory();
		StringBuffer sb = new StringBuffer();
		sb.append(XML_DECLARATION);

		if (islist) {
			sb.append("<certificates>");
		}
		sb.append(System.getProperty("line.separator"));

		for (SPSCertificateType cert : certificates) {

			JAXBElement<SPSCertificateType> je = objectFactory.createSPSCertificate(cert);

			sb.append(marshal(je));
			sb.append(System.getProperty("line.separator"));
		}
		if (islist) {
			sb.append("</certificates>");
		}

		String response = INFO_OPEN_TAG + encode(sb.toString()) + INFO_CLOSE_TAG;

		return response;
	}

	

}
